﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;

namespace MMDemo
{
    public enum OperateTypeSort
    {
        Select,
        Insert,
        Bubble,
        Quick,
        Shell,
    }
    class AnimationSort:InterfaceDataStructs
    {

        /// <summary>
        /// 类成员
        /// </summary>
        private Form Animation_Form = null;//演示窗体，用于构造函数的初始化
        private int Animation_width = 0;//演示窗体的宽度
        private int Animation_height = 0;//演示窗体的高度
       
        public Bitmap BufferBmp = null;//双缓冲画布
        private Graphics BufferGrap = null;//画笔
        private DrawHandler RefreshHandler = null;

        private string[] SaveSortData;//排序的数据
        private int SortDtaNum = 0;
        private int ElementWidth = 20;
        private int RemainY = 100;



        public AnimationSort(Form An_Form, DrawHandler refreshHandler, int An_Width, int An_Height)
        {
            this.Animation_Form = An_Form;
            this.RefreshHandler = refreshHandler;
            this.Animation_width = An_Width;
            this.Animation_height = An_Height;
            //设置画布和画笔
            BufferBmp = new Bitmap(this.Animation_width, this.Animation_height);
            BufferGrap = Graphics.FromImage(BufferBmp);
        }

        //重写初始化数据方法
        public void InitData()
        {
            ResetBuffer(Animation_width, Animation_height);
            switch (GlobalSort.operateType)
            {
                case OperateTypeSort.Bubble:
                default:
                    ResetData(GlobalSort.SortData); break;
            }
            DrawElement();
        }
        private bool Refresh()
        {
            try
            {
                if (Animation_Form.IsHandleCreated)
                    Animation_Form.Invoke(RefreshHandler);
            }
            catch (Exception ex)
            {
                MessageBox.Show(Animation_Form,ex.Message);
                return false;
            }
            return true;
        }
        public void ResetData()
        {
            InitData();
        }
        public void ResetData(string data)
        {
            SaveSortData = data.Split(','); ;
            SortDtaNum = SaveSortData.Length;
            data_one = -1;
            data_two = -1;
            IsCompare = false;
            IsMove = false;
            SortTempData = "";
        }
        public Bitmap GetBufferBmp()
        {
            return BufferBmp;
        }
        //重新设置双缓冲画布和Graphics
        public void ResetBuffer(int Width, int Height)
        {
            this.Animation_width = Width;
            this.Animation_height = Height;
            if (null != BufferBmp)
            {
                BufferBmp.Dispose();
                BufferBmp = null;
            }
            if (null != BufferGrap)
            {
                BufferGrap.Dispose();
                BufferGrap = null;
            }

            BufferBmp = new Bitmap(this.Animation_width, this.Animation_height);
            BufferGrap = Graphics.FromImage(BufferBmp);
            DrawElement();
        }

        private bool stop_flag = false;
        public void Animation()
        {
            switch (GlobalSort.operateType)
            {
                case OperateTypeSort.Select:
                    stop_flag = Animation_Select();
                    break;
                case OperateTypeSort.Insert:
                    stop_flag = Animation_Insert();
                    break;
                case OperateTypeSort.Bubble:
                    stop_flag = Animation_Bubble();
                    break;
                case OperateTypeSort.Quick:
                    stop_flag = Animation_Quick();
                    break;
                case OperateTypeSort.Shell:
                    stop_flag = Animation_Shell();
                    break;
            }

            if (!stop_flag)
            {
                MessageBox.Show(Animation_Form,"算法演示结束!");
                 SysMainForm.AnimationForm.ChangeExcuteOverBtnsEnable();
            }
        }

        private int data_one = -1;
        private int data_two = -1;
        private bool IsCompare = false;
        private bool IsMove = false;
        private bool IsAssignment = false;

        private bool Animation_Select()
        {
            SetExcuteLine(1);
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(2);
            SetExcuteLine(3);
            int i, j = 0;
            SetExcuteLine(4);
            int min;//声明整型变量min
            SetExcuteLine(5);
            for (i = 0; i < SortDtaNum - 1; ++i)
            {
                SetExcuteLine(6);
                SetExcuteLine(7);
                min = i;
                data_one = data_two = -1;
                DrawElement();
                Thread.Sleep(_Speed);
                SetExcuteLine(8);
                for (j = i + 1; j < SortDtaNum; j++)
                {
                    SetExcuteLine(9);
                    data_one = min;
                    data_two = j;
                    SetExcuteLine(10);
                    FlickerCompareElement();
                    if (Convert.ToInt32(SaveSortData[j]) < Convert.ToInt32(SaveSortData[min]))
                    {
                        SetExcuteLine(11);
                        min = j;
                    }
                    SetExcuteLine(12);
                    SetExcuteLine(8);
                }
                data_one = i;
                data_two = min;
                SetExcuteLine(13);
                FlickerMoveElement();
                string t = SaveSortData[min];
                SetExcuteLine(14);
                SaveSortData[min] = SaveSortData[i];
                SetExcuteLine(15);
                SaveSortData[i] = t;
                FlickerMoveElement();
                SetExcuteLine(16);
                SetExcuteLine(5);
            }


            Thread.Sleep(_Speed);
            FlickerCompareElement();
            SetExcuteLine(17);
            return false;
        }

        private bool Animation_Insert()
        {
            SetExcuteLine(1);
            SetExcuteLine(2);
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(3);
            int i, j;
            SetExcuteLine(4);
            for (i = 1; i < SortDtaNum; ++i) //最多可以做SortDtaNum趟排序
            {
                data_one = -2;
                data_two = i;
                SetExcuteLine(5);
                SetExcuteLine(6);
                FlickerAssignmentElement();
                SortTempData = SaveSortData[i];
                SaveSortData[i] = "0";
                FlickerAssignmentElement();
                SetExcuteLine(7);
                j = i;

                data_one = j - 1;
                data_two = -2;
                SetExcuteLine(8);
                FlickerCompareElement();
                while ((j > 0) && (Convert.ToInt32(SaveSortData[j - 1]) > Convert.ToInt32(SortTempData)))    //判断是否满足比较条件
                {
                    data_one = j;
                    data_two = j - 1;
                    SetExcuteLine(9);
                    SetExcuteLine(10);
                    FlickerAssignmentElement();
                    SaveSortData[j] = SaveSortData[j - 1];  //交换顺序
                    SaveSortData[j - 1] = "0";
                    FlickerAssignmentElement();
                    SetExcuteLine(11);
                    --j;
                    SetExcuteLine(12);
                    SetExcuteLine(8);
                    data_one = j - 1;
                    data_two = -2;
                    FlickerCompareElement();
                }
                data_one = j;
                data_two = -2;
                SetExcuteLine(13);
                FlickerAssignmentElement();
                SaveSortData[j] = SortTempData;
                SortTempData = "0";
                FlickerAssignmentElement();
                SetExcuteLine(14);
                SetExcuteLine(4);
            }
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(15);
            return false;
        }

        private bool Animation_Bubble()
        {
            SetExcuteLine(1);
            SetExcuteLine(2);
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(3);
            string temp;
            SetExcuteLine(4);
            int i, j;
            SetExcuteLine(5);
            for (i = 0; i < SortDtaNum;++i )
            {
                SetExcuteLine(6);
                SetExcuteLine(7);
                for (j = SortDtaNum - 2; j >= i;j-- )
                {
                    SetExcuteLine(8);
                    data_one = data_two = -1;
                    DrawElement();
                    Thread.Sleep(_Speed);
                    data_one = j + 1;
                    data_two = j;
                    SetExcuteLine(9);
                    FlickerCompareElement();
                    
                    if (Convert.ToInt32(SaveSortData[j+1])<Convert.ToInt32(SaveSortData[j]))
                    {
                        SetExcuteLine(10);
                        SetExcuteLine(11);
                        FlickerMoveElement();
                        temp = SaveSortData[j + 1];
                        SetExcuteLine(12);
                        SaveSortData[j + 1] = SaveSortData[j];
                        SetExcuteLine(13);
                        SaveSortData[j] = temp;
                        FlickerMoveElement();
                        SetExcuteLine(14);
                    }
                    SetExcuteLine(15);
                    SetExcuteLine(7);
                }
                Thread.Sleep(_Speed);
                SetExcuteLine(16);
                SetExcuteLine(5);
            }
            SetExcuteLine(17);
            return false;
        }

        private bool Animation_Quick()
        {
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(1);
            QuickSort(ref SaveSortData, SortDtaNum);
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(7);
            return false;
        }
        public void QuickSort(ref string[] data,int n)
        {
            QuickSort(ref data,0,n-1);
        }
        public void QuickSort(ref string[] data,int low,int high)
        {
            SetExcuteLine(2);
            if (low>=high)
            {
                SetExcuteLine(3);
                return;
            }
            SetExcuteLine(4);
            SetExcuteLine(9);
            int m = Partition(ref data, low, high);
            SetExcuteLine(5);
            QuickSort(ref data, low, m - 1);
            SetExcuteLine(6);
            QuickSort(ref data, m + 1, high);
        }

        public string SortTempData="";
        public int Partition(ref string[] data,int low,int high)
        {
            SetExcuteLine(10);
            int pos = low;
            data_one = -1;
            data_two = pos;
            SetExcuteLine(11);
            FlickerAssignmentElement();
            SortTempData = data[pos];
            data_one = -2;
            FlickerAssignmentElement();
            SetExcuteLine(12);
            for (int i = low + 1; i <= high;i++ )
            {
                data_one = i;
                data_two = -2;
                SetExcuteLine(13);
                FlickerCompareElement();
                if (Convert.ToInt32(data[i])<Convert.ToInt32(SortTempData))
                {
                    SetExcuteLine(14);
                    pos++;
                    SetExcuteLine(15);
                    if (pos!=i)
                    {
                        data_one = i;
                        data_two = pos;
                        SetExcuteLine(16);
                        SetExcuteLine(17);
                        FlickerMoveElement();
                        string temp;
                        temp = data[i];
                        SetExcuteLine(18);
                        data[i] = data[pos];
                        SetExcuteLine(19);
                        data[pos] = temp;
                        FlickerMoveElement();
                        SetExcuteLine(20);
                    }
                    SetExcuteLine(21);
                }
                SetExcuteLine(22);
                SetExcuteLine(12);
            }
            data_one = low;
            data_two = pos;
            SetExcuteLine(23);
            FlickerMoveElement();
            data[low] = data[pos];
            SetExcuteLine(24);
            data[pos] = SortTempData;
            FlickerMoveElement();
            SetExcuteLine(25);
            SetExcuteLine(26);
            return pos;
        }



        public bool Animation_Shell()
        {
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(1);
            Shellsort(ref SaveSortData, 0, SortDtaNum - 1);
            DrawElement();
            Thread.Sleep(_Speed);
            SetExcuteLine(23);
            return false;
        }
        public void Shellsort(ref string[]data,int left,int right)
        {
            SetExcuteLine(2);
            SetExcuteLine(3);
            int i, j, gap;
            SetExcuteLine(4);
            gap = right - left + 1;
            SetExcuteLine(5);
            do
            {
                SetExcuteLine(6);
                SetExcuteLine(7);
                gap = gap / 3 + 1;
                SetExcuteLine(8);
                for (i = left + gap; i <= right;i++ )
                {
                    SetExcuteLine(9);
                    data_one = i;
                    data_two = i - gap;
                    SetExcuteLine(10);
                    FlickerCompareElement();
                    if (Convert.ToInt32(data[i])<Convert.ToInt32(data[i-gap]))
                    {
                        SetExcuteLine(11);
                        data_one = data_two = i;
                        SetExcuteLine(12);
                        FlickerAssignmentElement();
                        SortTempData = data[i];
                        data[i] = "0";
                        data_one = -2;
                        FlickerAssignmentElement();
                        SetExcuteLine(13);
                        j = i - gap;
                        SetExcuteLine(14);
                        do 
                        {
                            SetExcuteLine(15);
                            data_one = j + gap; data_two = j;
                            SetExcuteLine(16);
                            FlickerAssignmentElement();
                            data[j + gap] = data[j];
                            data[j] = "0";
                            FlickerAssignmentElement();
                            SetExcuteLine(17);
                            j = j - gap;
                            SetExcuteLine(18);
                            data_one = -2;
                            data_two = j;
                            FlickerCompareElement();
                        } while (j>=left&&Convert.ToInt32(SortTempData)<Convert.ToInt32(data[j]));

                        data_one = j + gap; data_two = -2;
                        SetExcuteLine(19);
                        FlickerAssignmentElement();
                        data[j + gap] = SortTempData;
                        SortTempData = "0";
                        FlickerAssignmentElement();
                        SetExcuteLine(20);
                    }
                    SetExcuteLine(21);
                    SetExcuteLine(8);
                }
                SetExcuteLine(22);
            } while (gap > 1);
        }



        private void FlickerCompareElement()
        {
            for (int i = 1; i <= 6; ++i)
            {
                Thread.Sleep(_Speed/3);
                if (i % 2 != 0)
                {
                    IsCompare = true;
                    IsMove = false;
                    IsAssignment = false;
                }
                else
                {
                    IsCompare = false;
                    IsMove = false;
                    IsAssignment = false;
                }
                DrawElement();
            }
        }
        private void FlickerMoveElement()
        {
            for (int i = 1; i <= 4; ++i)
            {
                Thread.Sleep(_Speed/3);
                if (i % 2 != 0)
                {
                    IsCompare = false;
                    IsMove = true;
                    IsAssignment = false;
                }
                else
                {
                    IsCompare = false;
                    IsMove = false;
                    IsAssignment = false;
                }
                DrawElement();
            }
        }

        private void FlickerAssignmentElement()
        {
            for (int i = 1; i <= 4; ++i)
            {
                Thread.Sleep(_Speed/3);
                if (i % 2 != 0)
                {
                    IsCompare = false;
                    IsMove = false;
                    IsAssignment = true;

                }
                else
                {
                    IsCompare = false;
                    IsMove = false;
                    IsAssignment = false;
                }
                DrawElement();
            }
        }
        public void DrawElement()
        {
            BufferGrap.DrawImage(PublicDataClass.DemoPicture, 0, 0, Animation_width, Animation_height);
            if (SortTempData!=""&&SortTempData!="0")
            {
                int x = 15;
                int y=Convert.ToInt32(SortTempData)*4;
                BufferGrap.DrawRectangle(new Pen(Color.YellowGreen, 3), x, Animation_height - RemainY -y , ElementWidth, y);
                BufferGrap.DrawString(SortTempData, new Font("微软雅黑", 15), new SolidBrush(Color.YellowGreen), x, Animation_height - RemainY - y - 30);
                BufferGrap.FillRectangle(new SolidBrush(Color.Blue), x, Animation_height - RemainY - y, ElementWidth, y);
                if (-2 == data_one || -2 == data_two)
                {
                    if (IsCompare)
                    {
                        BufferGrap.FillRectangle(new SolidBrush(Color.Yellow), x, Animation_height - RemainY - y, ElementWidth, y);
                    }
                    else if (IsMove)
                    {
                        BufferGrap.FillRectangle(new SolidBrush(Color.Red), x, Animation_height - RemainY - y, ElementWidth, y);
                    }
                    else if (IsAssignment)
                    {
                        BufferGrap.FillRectangle(new SolidBrush(Color.Green), x, Animation_height - RemainY - y, ElementWidth, y);
                    }
                }
            }
            for (int i =0;i<SortDtaNum;++i)
            {
                if (SaveSortData[i]!="0")
                {               
                    int x = (i + 1) * Animation_width / (SortDtaNum + 1) - ElementWidth / 2;
                    int y = Convert.ToInt32(SaveSortData[i]) * 4;
                    BufferGrap.DrawRectangle(new Pen(Color.YellowGreen, 3), x, Animation_height - RemainY - y, ElementWidth, y);
                    BufferGrap.DrawString(SaveSortData[i], new Font("微软雅黑", 15), new SolidBrush(Color.YellowGreen), x, Animation_height - RemainY - y - 30);
                    BufferGrap.FillRectangle(new SolidBrush(Color.Blue), x, Animation_height - RemainY - y, ElementWidth, y);
                    if (i==data_one||i==data_two)
                    {
                        if (IsCompare)
                        {
                            BufferGrap.FillRectangle(new SolidBrush(Color.Yellow), x, Animation_height - RemainY - y, ElementWidth, y);
                        }
                        else if (IsMove)
                        {
                            BufferGrap.FillRectangle(new SolidBrush(Color.Red), x, Animation_height - RemainY - y, ElementWidth, y);
                        }
                        else if (IsAssignment)
                        {
                            BufferGrap.FillRectangle(new SolidBrush(Color.Green), x, Animation_height - RemainY - y, ElementWidth, y);
                        }
                    }
                    
                } 
            }
            Refresh();
        }

        private const int SPEED = 1000;
        private int _Speed = SPEED;
        public void SetSpeed(float scale)
        {
            _Speed =  (int)(SPEED * scale);
        }

        private void SetExcuteLine(int line)
        {
            if (line != GlobalBinTree.cur_line)
            {
                GlobalSort.cur_line = line;
                Thread.Sleep((int)(1000 * PublicDataClass.scale));
                SysMainForm.AnimationForm.SetSelectLine(line);
            }
        }
    }
}
